#define NCLIB_MAIN
#include "register.cc"
using namespace noria;

#include <string>
#include <unordered_set>
#include <unordered_map>
using namespace std;

#ifdef _WINDOWS
#define WIN32_LEAN_AND_MEAN
#include <windows.h>

BOOL APIENTRY DllMain(HMODULE hModule,
	DWORD  ul_reason_for_call,
	LPVOID lpReserved
	)
{
	switch (ul_reason_for_call)
	{
	case DLL_PROCESS_ATTACH:
	{
		//Activator::RegisterTypes("libnc", RegisterTypes);
		break;
	}
	case DLL_THREAD_ATTACH: break;
	case DLL_THREAD_DETACH: break;
	case DLL_PROCESS_DETACH:
	{
		//Cleanup();
		break;
	}
	}
	return TRUE;
}
#else
#endif


class Hashmap final : public ITypeCollection
{
public:
	//Hashmap()
	//{
	//}
	//Hashmap(const Hashmap& ref)
	//{
	//	throw runtime_error("Hashmap doesn't support copy operation");
	//}
	//Hashmap(Hashmap&& ref)
	//{
	//}
public:
	virtual void Add(const char* name, const IType* type) override
	{
		m_map.insert({name, type});
	}
	const IType* operator[] (const char* name) const
	{
		auto it = m_map.find(name);
		if (it != m_map.end())
		{
			return it->second;
		}
		return nullptr;
	}
public:
	virtual void Dispose() override
	{
	}
private:
	unordered_map<string, const IType*> m_map;
};

/*
 *	!!no thread safe!!
 */
static unordered_map<string, Hashmap> &GetTypesCache()
{
	static unordered_map<string, Hashmap> map;
	static bool initialized = false;

	if (!initialized)
	{
		RegisterTypes(&map["libnc"]);
		initialized = true;
	}

	return map;
}

/*
 *	!!no thread safe!!
 */
int NcCreate(const char* library, const char* type, void** reflectable)
{
	static auto &map = GetTypesCache();
	static unordered_set<string> set {"libnc"};

	if (set.find(library) == set.end())
	{
		::LoadLibraryA(library);
		set.insert(library);
	}

	try
	{
		const IType* tc = map[library][type];
		if (!tc)
		{
			*reflectable = nullptr;
			return 2;
		}

		*reflectable = tc->CreateInstance();
		return 0;
	}
	catch (const exception&)
	{
		*reflectable = nullptr;
		return 1;
	}
}

/*
 *	!!no thread safe!!
 */
int NcRegister(const char* library, RegisterCallback callback)
{
	static auto &map = GetTypesCache();

	ITypeCollection* collection = &map[library];
	callback(collection);
	return 0;
}

